home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 037a / exec31.zip / CHECKPAT.ASM < prev    next >
Assembly Source File  |  1991-08-16  |  20KB  |  1,029 lines

  1. ;
  2. ;    --- Version 3.1 91-08-16 16:32 ---
  3. ;
  4. ;    CHECKPAT.ASM - Utility function to check a given file/path,
  5. ;            and to resolve an incomplete path.
  6. ;            (Does not use any undocumented DOS functions.)
  7. ;
  8. ;    Public Domain Software written by
  9. ;        Thomas Wagner
  10. ;        Ferrari electronic GmbH
  11. ;        Beusselstrasse 27
  12. ;        D-1000 Berlin 21
  13. ;        Germany
  14. ;
  15. ;>e
  16. ; Assemble with
  17. ;
  18. ; tasm  /DPASCAL checkpat,checkpap           - Turbo Pascal (Tasm only), near
  19. ; tasm  /DPASCAL /DFARCALL checkpat,checkpap - Turbo Pascal (Tasm only), far
  20. ; ?asm  checkpat;                   - C, default model (small)
  21. ; ?asm  /DMODL=large checkpat               - C, large model
  22. ;
  23. ;    NOTE:    For C, change the 'model' directive below according to your
  24. ;        memory model, or define MODL=xxx on the command line.
  25. ;
  26. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  27. ;        command line, or define it here.
  28. ;
  29. ;
  30. ;   This routine accepts a file name and/or path, checks and resolves the
  31. ;   path, and splits the name into its components.
  32. ;
  33. ;   A relative path, or no path at all, is resolved to a full path
  34. ;   specification. An invalid disk drive will not cause the routine 
  35. ;   to fail.
  36. ;
  37. ;   PASCAL:
  38. ;    function checkpath (name    : string,
  39. ;                        drive   : string,
  40. ;                        dir     : string,
  41. ;                        fname   : string,
  42. ;                        ext     : string,
  43. ;                        fullpath: string)
  44. ;                : integer;
  45. ;   C:
  46. ;    int checkpath (char *name,     
  47. ;                   char *drive,      
  48. ;                   char *dir,        
  49. ;                   char *fname,      
  50. ;                   char *ext,        
  51. ;                   char *fullpath);  
  52. ;
  53. ;   Parameters:
  54. ;
  55. ;    name     - Input:  file name and/or path string
  56. ;    drive     - Output: drive letter, with trailing colon
  57. ;    dir     - Output: directory, with leading and trailing bakslash
  58. ;    fname     - Output: file name
  59. ;    ext     - Output: file extension, with leading dot
  60. ;    fullpath - Output: combined path
  61. ;
  62. ;    NOTE:    The input 'name' and the output 'fullpath' parameters may
  63. ;        both point to the same string. The 'fullpath' pointer will
  64. ;        only be used after completion of input parsing.
  65. ;
  66. ;    NOTE:    For Pascal, reserve one character in addition to the
  67. ;        standard maximum length for all strings, including the
  68. ;        input parameter. All strings will be zero-terminated
  69. ;        during internal processing. DO NOT pass a constant as
  70. ;        input parameter string.
  71. ;
  72. ;   Returns:
  73. ;
  74. ;    A negative value on error:
  75. ;
  76. ;        ERR_DRIVE       -1    Invalid drive
  77. ;        ERR_PATH        -2    Invalid path
  78. ;        ERR_FNAME       -3    Malformed filename
  79. ;        ERR_DRIVECHAR   -4    Illegal drive letter
  80. ;        ERR_PATHLEN     -5    Path too long
  81. ;        ERR_CRITICAL    -6    Critical error (invalid drive, drive not ready)
  82. ;
  83. ;    On error, all output strings except the drive string will be empty.
  84. ;
  85. ;    If no error occured, a positive value consisting of the bitwise OR 
  86. ;    of the following flags:
  87. ;
  88. ;        HAS_WILD        1     Filename/ext has wildcard characters
  89. ;        HAS_EXT         2     Extension specified
  90. ;        HAS_FNAME       4     Filename specified
  91. ;        HAS_PATH        8     Path specified
  92. ;        HAS_DRIVE       0x10  Drive specified
  93. ;
  94. ;            Those flags are set only if the corresponding 
  95. ;            component was given in the input string. The 
  96. ;            'drive' and 'dir' strings will always contain 
  97. ;            the resolved drive and path.
  98. ;
  99. ;        FILE_EXISTS     0x20  File exists, upper byte has attributes
  100. ;        IS_DIR        0x1000  Directory, upper byte has attributes
  101. ;
  102. ;        The file attributes returned if FILE_EXISTS or IS_DIR 
  103. ;        is set are
  104. ;            0x0100 - Read only
  105. ;            0x0200 - Hidden
  106. ;            0x0400 - System
  107. ;            0x2000 - Archive
  108. ;            0x4000 - Device
  109. ;
  110. ;<
  111. ;>d
  112. ; Assemblierung mit
  113. ;
  114. ; tasm  /DPASCAL checkpat,checkpatp          - Turbo Pascal (nur Tasm), near
  115. ; tasm  /DPASCAL /DFARCALL checkpat,checkpatp - Turbo Pascal (nur Tasm), far
  116. ; ?asm  checkpat;                    - C, default model (small)
  117. ; ?asm  /DMODL=large checkpat                - C, large model
  118. ;
  119. ;    HINWEIS: Für C können Sie entweder die folgende 'model'-Direktive
  120. ;        Ihrem Speichermodell entsprechend ändern, oder beim
  121. ;        Assemblieren MODL=xxx in der Kommandozeile definieren.
  122. ;
  123. ;        Für Turbo C Huge model müssen Sie /DTC_HUGE beim Assemblieren
  124. ;        angeben, oder das Symbol in dieser Quelle definieren.
  125. ;
  126. ;   Diese Routine erwartet einen Dateinamen und/oder Pfad, prüft ihn
  127. ;   und löst den Pfad auf, und teilt den Namen in seine Komponenten.
  128. ;
  129. ;   Ein relativer Pfad, oder eine fehlende Pfadangabe, wird in eine
  130. ;   absolute Pfadangabe konvertiert. Ein ungültiger Laufwerksbuchstabe
  131. ;   führt nicht zum Abbruch.
  132. ;
  133. ;   PASCAL:
  134. ;    function checkpath (name    : string,
  135. ;                        drive   : string,
  136. ;                        dir     : string,
  137. ;                        fname   : string,
  138. ;                        ext     : string,
  139. ;                        fullpath: string)
  140. ;                : integer;
  141. ;   C:
  142. ;    int checkpath (char *name,     
  143. ;                   char *drive,      
  144. ;                   char *dir,        
  145. ;                   char *fname,      
  146. ;                   char *ext,        
  147. ;                   char *fullpath);  
  148. ;
  149. ;   Parameter:
  150. ;
  151. ;    name     - Input:  Filename und/oder Pfad
  152. ;    drive     - Output: Laufwerksbuchstabe, mit abschließendem Doppelpunkt
  153. ;    dir     - Output: Directory, mit führendem und abschließendem '\'
  154. ;    fname     - Output: Filename
  155. ;    ext     - Output: File extension, mit führendem Punkt
  156. ;    fullpath - Output: Kombinierter Pfad
  157. ;
  158. ;   Liefert:
  159. ;
  160. ;    Einen negativen Wert bei Fehler:
  161. ;
  162. ;        ERR_DRIVE       -1    Ungültiges Laufwerk
  163. ;        ERR_PATH        -2    Ungültiger Pfad
  164. ;        ERR_FNAME       -3    Fehlerhafter Dateiname
  165. ;        ERR_DRIVECHAR   -4    Illegaler Laufwerksbuchstabe
  166. ;        ERR_PATHLEN     -5    Pfad zu lang
  167. ;        ERR_CRITICAL    -6    Critical error (Illegales Laufwerk,
  168. ;                      Laufwerk nicht bereit)
  169. ;
  170. ;    Bei Fehler sind alle Ausgabestrings außer 'drive' leer.
  171. ;
  172. ;    Wenn kein Fehler auftrat einen positiven Wert der aus dem
  173. ;    bitweisen OR der folgenden Flags besteht:
  174. ;
  175. ;        HAS_WILD        1     Filename/ext enthält Wildcard-Zeichen
  176. ;        HAS_EXT         2     Extension angegeben
  177. ;        HAS_FNAME       4     Filename angegeben
  178. ;        HAS_PATH        8     Pfad angegeben
  179. ;        HAS_DRIVE       0x10  Laufwerk angegeben
  180. ;
  181. ;            Diese Flags sind nur gesetzt wenn die entsprechende 
  182. ;            Komponente im Eingabestring enthalten war. Die 
  183. ;            'drive' und 'dir' Ausgabestrings enthalten stets 
  184. ;            den aufgelösten Laufwerks- und Pfadstring.
  185. ;
  186. ;        FILE_EXISTS     0x20  Datei existiert, Attribute im oberen Byte
  187. ;        IS_DIR        0x1000  Directory, Attribute im oberen Byte
  188. ;
  189. ;        Die Dateiattribute die geliefert werden wenn FILE_EXISTS 
  190. ;        oder IS_DIR gesetzt ist sind:
  191. ;
  192. ;            0x0100 - Read only
  193. ;            0x0200 - Hidden
  194. ;            0x0400 - System
  195. ;            0x2000 - Archive
  196. ;            0x4000 - Device
  197. ;
  198. ;<
  199. ;
  200.     IFDEF    PASCAL
  201.     .model    tpascal
  202.     IFDEF    FARCALL
  203.     %out    Pascal, far calls
  204.     ELSE
  205.     %out    Pascal, near calls
  206.     ENDIF
  207. ptrsize    =    1
  208.     ELSE
  209.     IFNDEF    MODL
  210.     .model    small,c
  211.     %out    small model
  212.     ELSE
  213. %    .model    MODL,c
  214. %    %out    MODL model
  215.     ENDIF
  216. ptrsize    =    @DataSize
  217.     ENDIF
  218. ;
  219. ldds    macro    reg,var
  220.     IF    ptrsize
  221.     lds    reg,var
  222.     ELSE
  223.     mov    reg,var
  224.     ENDIF
  225.     endm
  226. ;
  227. lddsf    macro    reg,var
  228.     IF    ptrsize
  229.     lds    reg,var
  230.     ELSE
  231.     mov    ds,dseg
  232.     mov    reg,var
  233.     ENDIF
  234.     endm
  235. ;
  236. ldes    macro    reg,var
  237.     IF    ptrsize
  238.     les    reg,var
  239.     ELSE
  240.     mov    reg,var
  241.     ENDIF
  242.     endm
  243. ;
  244. ldesf    macro    reg,var
  245.     IF    ptrsize
  246.     les    reg,var
  247.     ELSE
  248.     mov    es,dseg
  249.     mov    reg,var
  250.     ENDIF
  251.     endm
  252. ;
  253.     public    checkpath
  254.     public    exists
  255. ;
  256. ERR_DRIVE    =    -1
  257. ERR_PATH    =    -2
  258. ERR_FNAME    =    -3
  259. ERR_DRIVECHAR    =    -4
  260. ERR_PATHLEN    =    -5
  261. ERR_CRITICAL    =    -6
  262. ;
  263. HAS_WILD    =    1
  264. HAS_EXT        =    2
  265. HAS_FNAME    =    4
  266. HAS_PATH    =    8
  267. HAS_DRIVE    =    10h
  268. FILE_EXISTS    =    20h
  269. IS_DIR        =    1000h
  270. ;
  271. MAXPATH        =    66
  272. ;
  273.     IFDEF    PASCAL
  274.     .data
  275.     ELSE
  276.     IFDEF    TC_HUGE
  277.     .fardata?    checkpat_data
  278.     ELSE
  279.     .data?
  280.     ENDIF
  281.     ENDIF
  282. ;
  283. save24        label    dword
  284. sav24_off    dw    ?
  285. sav24_seg    dw    ?
  286. fail        dw    ?
  287. dfltpath    db    68 dup(?)
  288. ;
  289.     .code
  290. ;
  291. @strcpy    proc    near
  292.     lodsb
  293.     stosb
  294.     or    al,al
  295.     jnz    @strcpy
  296.     dec    di
  297.     ret
  298. @strcpy    endp
  299. ;
  300.     IFDEF    PASCAL
  301. @strlen    proc    near
  302.     push    di
  303.     inc    di
  304.     xor    ax,ax
  305.     mov    cx,-1
  306.     repne scasb
  307.     not    cx
  308.     dec    cx
  309.     pop    di
  310.     mov    es:[di],cl
  311.     ret
  312. @strlen    endp
  313.     ENDIF
  314. ;
  315. @int24_handler    proc far
  316.     push    ds
  317.     IFDEF    TC_HUGE
  318.     mov    ax,SEG checkpat_data
  319.     ELSE
  320.     IFDEF    PASCAL
  321.     mov    ax,SEG fail
  322.     ELSE
  323.     mov    ax,SEG DGROUP
  324.     ENDIF
  325.     ENDIF
  326.     mov    ds,ax
  327.     mov    fail,1
  328.     pop    ds
  329.     xor    ax,ax        ; ignore (for compatibility with DOS < 3.1)
  330.     iret
  331. @int24_handler    endp
  332. ;
  333. ;
  334.     IFDEF    PASCAL
  335.     IFDEF    FARCALL
  336. checkpath PROC far uses ds, string: dword, drive: dword, path: dword, fname: dword, ext: dword, fullpath: dword
  337.     ELSE
  338. checkpath PROC near uses ds, string: dword, drive: dword, path: dword, fname: dword, ext: dword, fullpath: dword
  339.     ENDIF
  340.     ELSE
  341. checkpath PROC uses ds si di, string: ptr byte, drive: ptr byte, path: ptr byte, fname: ptr byte, ext: ptr byte, fullpath: ptr byte
  342.     ENDIF
  343.     local    drv: word,flags:word,dseg: word
  344. ;
  345.     IFDEF    TC_HUGE
  346.     mov    ax,SEG my_data
  347.     mov    ds,ax
  348.     ENDIF
  349.     mov    dseg,ds
  350.     IFDEF    PASCAL
  351.     cld
  352.     ENDIF
  353. ;
  354. ;    save old critical error handler, install own
  355. ;
  356.     mov    ax,3524h
  357.     int    21h
  358.     mov    sav24_off,bx
  359.     mov    sav24_seg,es
  360.     mov    fail,0
  361.     mov    ax,cs
  362.     mov    ds,ax
  363.     mov    dx,offset @int24_handler
  364.     mov    ax,2524h
  365.     int    21h
  366.     mov    ds,dseg
  367. ;
  368. ;    Init output strings & flags
  369. ;
  370.     xor    ax,ax
  371.     mov    flags,ax
  372.     ldesf    di,path
  373.     IFDEF    PASCAL
  374.     stosw
  375.     ELSE
  376.     stosb
  377.     ENDIF
  378.     ldes    di,fname
  379.     IFDEF    PASCAL
  380.     stosw
  381.     ELSE
  382.     stosb
  383.     ENDIF
  384.     ldes    di,ext
  385.     IFDEF    PASCAL
  386.     stosw
  387.     ELSE
  388.     stosb
  389.     ENDIF
  390. ;
  391. ;------ Check the drive. If none was given, use current drive.
  392. ;
  393.     ldes    di,drive
  394.     IFDEF    PASCAL
  395.     inc    di
  396.     ENDIF
  397.     ldds    si,string
  398.     IFDEF    PASCAL
  399. ; for pascal, zero-terminate input string
  400.     lodsb
  401.     mov    bl,al
  402.     xor    ah,ah
  403.     mov    [si+bx],ah
  404.     ENDIF
  405. ;
  406. ; skip leading whitespace
  407. ;
  408. skip_space:
  409.     lodsb
  410.     cmp    al,' '
  411.     je    skip_space
  412.     cmp    al,09h
  413.     je    skip_space
  414.     dec    si
  415. ;
  416.     or    al,al
  417.     jz    no_drive
  418.     cmp    byte ptr 1[si],':'
  419.     je    drive_there
  420. ;
  421. no_drive:
  422.     mov    ah,19h            ; get default drive
  423.     int    21h
  424.     add    al,'A'
  425.     stosb
  426.     mov    bl,al
  427.     mov    al,':'
  428.     stosb
  429.     jmp    short check_drive
  430. ;
  431. badchar:
  432.     mov    ax,ERR_DRIVECHAR
  433.     jmp    error_exit
  434. ;
  435. drive_there:
  436.     inc    si
  437.     and    al,NOT 20h        ; convert to uppercase
  438.     cmp    al,'A'
  439.     jb    badchar
  440.     cmp    al,'A'+1fh        ; Novell allows some strange chars
  441.     ja    badchar
  442.     stosb
  443.     or    flags,HAS_DRIVE
  444.     mov    bl,al
  445.     movsb
  446. ;
  447. ;    Now check the drive for validity by getting the current directory
  448. ;    of this drive (we need it anyway later on)
  449. ;
  450. check_drive:
  451.     and    bx,1fh
  452.     mov    drv,bx
  453.     xor    al,al
  454.     stosb
  455. ;
  456.     push    ds
  457.     push    si
  458. ;
  459.     mov    ax,dseg
  460.     mov    ds,ax
  461.     mov    es,ax
  462.     mov    si,offset dfltpath+3
  463.     mov    ah,47h        ; get current directory
  464.     mov    dx,drv        ; drive number
  465.     int    21h
  466.     jc    cpath_bad
  467.     cmp    fail,0
  468.     je    cpath_good
  469. ;
  470. ;    Get dir returned an error -> the drive is invalid.
  471. ;
  472. cpath_bad:
  473.     add    sp,4
  474.     mov    ax,ERR_DRIVE
  475.     jmp    error_exit    ; can't continue with invalid drive
  476. ;
  477. ;    The drive is valid, edit the current path to include
  478. ;    leading drive letter, colon, and backslash.
  479. ;    Also, copy the path into the path output string, in case no
  480. ;    path is given in the input, and append trailing backslash to it.
  481. ;
  482. cpath_good:
  483.     mov    di,offset dfltpath
  484.     mov    ax,drv
  485.     add    al,'A'-1
  486.     stosb
  487.     mov    al,':'
  488.     stosb
  489.     mov    si,di        ; point to start of path
  490.     mov    al,'\'
  491.     stosb
  492.     ldes    di,path
  493.     IFDEF    PASCAL
  494.     inc    di
  495.     ENDIF
  496.     call    @strcpy
  497.     mov    al,'\'
  498.     cmp    byte ptr es:[di-1],al    ; root dir?
  499.     je    drive_ok        ; then no second backslash
  500.     stosb                ; else append backslash
  501.     xor    al,al
  502.     stosb                ; and zero
  503. ;
  504. ;
  505. ;------ Drive checked, is valid. Now separate path and filename.
  506. ;
  507. drive_ok:
  508.     pop    si
  509.     pop    ds
  510.     mov    di,si
  511.     mov    ax,ds
  512.     mov    es,ax
  513.     push    si
  514. ;
  515. ;    find the end of the string
  516. ;
  517.     xor    ax,ax
  518.     mov    cx,-1
  519.     repne scasb
  520.     mov    si,di
  521.     not    cx
  522.     dec    cx
  523.     jnz    has_fnp        ; continue if there's more in the string
  524.     add    sp,2
  525.     jmp    check_fname    ; exit if no path or filename
  526. ;
  527. ;    search from the end for slash/backslash
  528. ;
  529. has_fnp:
  530.     ldes    di,path
  531.     IFDEF    PASCAL
  532.     inc    di
  533.     ENDIF
  534.     sub    si,2        ; last char of string
  535.     mov    bx,5c2fh    ; the two slashes
  536.     std            ; backwards scan
  537. ;
  538. spath:
  539.     lodsb
  540.     cmp    al,bl
  541.     je    pfound
  542.     cmp    al,bh
  543.     je    pfound
  544.     loop    spath
  545. ;
  546. ;    no slash/backslash -> no path given
  547. ;
  548.     cld
  549.     pop    si
  550.     xor    cx,cx
  551.     jmp    short cfname
  552. ;
  553. longpath:
  554.     mov    ax,ERR_PATHLEN
  555.     jmp    error_exit
  556. ;
  557. ;    copy the path (note: CX has length of path including slash)
  558. ;
  559. pfound:
  560.     cld
  561.     pop    si
  562.     cmp    cx,MAXPATH
  563.     ja    longpath
  564.     or    flags,HAS_PATH        ; we have a path
  565.     push    cx
  566.     rep movsb
  567.     pop    cx
  568. ;
  569. ;    check for special filenames '.' and '..', and add them to
  570. ;    the path if present.
  571. ;    The special form that adds a '.' for every level further down
  572. ;    the tree is recognized, and translated into the DOS-form '..\'
  573. ;
  574. cfname:
  575.     cmp    byte ptr [si],'.'
  576.     jne    path_finished
  577.     cmp    byte ptr [si+1],'.'
  578.     je    is_special
  579.     cmp    byte ptr [si+1],0
  580.     jne    path_finished
  581. ;
  582. is_special:
  583.     or    flags,HAS_PATH        ; we have a path
  584.     mov    bx,MAXPATH
  585.     sub    bx,cx
  586.     mov    cx,2
  587.     lodsb
  588. ;
  589. copy_special:
  590.     or    bx,bx
  591.     jz    longpath
  592.     dec    bx
  593.     stosb
  594.     lodsb
  595.     or    al,al
  596.     jz    special_finished
  597.     cmp    al,'.'
  598.     jne    badname
  599.     loop    copy_special
  600. ;
  601. add_special:
  602.     sub    bx,3
  603.     jle    longpath
  604.     mov    al,'\'
  605.     stosb
  606.     mov    al,'.'
  607.     stosb
  608.     stosb
  609.     lodsb
  610.     or    al,al
  611.     jz    special_finished
  612.     cmp    al,'.'
  613.     jne    badname
  614.     jmp    add_special
  615. ;
  616. badname:
  617.     mov    ax,ERR_FNAME
  618.     jmp    error_exit
  619. ;
  620. special_finished:
  621.     dec    si
  622.     mov    al,'\'
  623.     stosb
  624. ;
  625. ;    now copy the filename and extension (limited to 8/3 chars)
  626. ;
  627. path_finished:
  628.     xor    al,al            ; terminate path
  629.     stosb
  630. ;
  631.     mov    bx,2a3fh        ; the two wildcards '*' and '?'
  632.     ldes    di,fname
  633.     IFDEF    PASCAL
  634.     inc    di
  635.     ENDIF
  636.     mov    cx,8            ; max 8 for name
  637. ;
  638. cfnloop:
  639.     lodsb
  640.     or    al,al            ; end of string?
  641.     jz    cfndot
  642.     cmp    al,'.'
  643.     je    cfndot
  644.     jcxz    cfnloop            ; skip if 8 chars copied
  645.     stosb
  646.     dec    cx
  647.     or    flags,HAS_FNAME
  648.     cmp    al,bl            ; check for wildcards    
  649.     je    fnwild
  650.     cmp    al,bh
  651.     jne    cfnloop
  652. ;
  653. fnwild:
  654.     or    flags,HAS_WILD
  655.     jmp    cfnloop
  656. ;
  657. cfndot:
  658.     mov    ah,al            ; save terminator (0 or '.')
  659.     xor    al,al
  660.     stosb                ; terminate filename
  661.     or    ah,ah
  662.     jz    no_ext            ; jump if at end of string
  663. ;
  664. ;    extension present, copy it.
  665. ;
  666.     or    flags,HAS_EXT
  667.     ldes    di,ext
  668.     IFDEF    PASCAL
  669.     inc    di
  670.     ENDIF
  671.     mov    cx,3
  672.     mov    al,ah
  673.     stosb                ; store '.' as first ext char
  674. ;
  675. cextloop:
  676.     lodsb
  677.     or    al,al
  678.     jz    cextend
  679.     stosb
  680.     cmp    al,bl            ; check for wildcards    
  681.     je    extwild
  682.     cmp    al,bh
  683.     jne    cextcont
  684. ;
  685. extwild:
  686.     or    flags,HAS_WILD
  687. ;
  688. cextcont:
  689.     loop    cextloop
  690. ;
  691. cextend:
  692.     xor    al,al
  693.     stosb                ; terminate extension
  694. ;
  695. ;
  696. no_ext:
  697.     test    flags,HAS_PATH
  698.     jz    check_fname
  699. ;
  700. ;    A path was specified, check it:
  701. ;    Change the current directory to the one specified. 
  702. ;    If valid, read back the new directory string 
  703. ;    (which has '.' and '..' resolved).
  704. ;    In any case, restore the current directory.
  705. ;
  706.     ldes    di,fullpath    ; make path string from drive and path
  707.     IFDEF    PASCAL
  708.     inc    di
  709.     ENDIF
  710.     ldds    si,drive
  711.     IFDEF    PASCAL
  712.     inc    si
  713.     ENDIF
  714.     call    @strcpy
  715.     ldds    si,path
  716.     IFDEF    PASCAL
  717.     inc    si
  718.     ENDIF
  719.     call    @strcpy
  720.     cmp    byte ptr es:[di-2],':'    ; root dir ?
  721.     je    no_slstrip        ; then don't strip backslash
  722.     mov    byte ptr es:[di-1],0    ; else remove trailing '\'
  723. ;
  724. no_slstrip:
  725.     xor    cx,cx        ; cx is 'path ok' flag (init to not ok)
  726.     ldds    dx,fullpath
  727.     IFDEF    PASCAL
  728.     inc    dx
  729.     ENDIF
  730.     ldes    di,path
  731.     IFDEF    PASCAL
  732.     inc    di
  733.     ENDIF
  734.     mov    ah,3bh        ; change current directory
  735.     int    21h
  736.     mov    ds,dseg
  737.     jc    rest_path    ; skip dir reading if invalid
  738.     cmp    fail,0
  739.     jne    rest_path
  740. ;
  741. ;    read back path
  742. ;
  743.     ldds    si,path
  744.     IFDEF    PASCAL
  745.     inc    si
  746.     ENDIF
  747.     inc    si        ; leave space for leading '\'
  748.     mov    ah,47h        ; get current directory
  749.     mov    dx,drv        ; drive number
  750.     int    21h
  751.     mov    ds,dseg
  752.     jc    rest_path    ; shouldn't happen, but...
  753.     cmp    fail,0
  754.     jne    rest_path
  755. ;
  756.     mov    byte ptr es:[di],'\'    ; prefix with '\'
  757.     xor    ax,ax
  758.     mov    cx,-1
  759.     repne scasb            ; find end of string
  760.     not    cx
  761.     cmp    cx,2
  762.     je    rest_path        ; don't append trailing '\' if root
  763.     mov    byte ptr es:[di-1],'\'
  764.     stosb                ; terminate
  765. ;
  766. rest_path:
  767.     mov    dx,offset dfltpath
  768.     mov    ah,3bh
  769.     int    21h
  770. ;
  771. ;    was the path ok?
  772. ;
  773.     or    cx,cx
  774.     jnz    check_fname
  775. ;
  776. ;    exit if not
  777. ;
  778.     mov    ax,ERR_PATH
  779.     jmp    error_exit
  780. ;
  781. ;    the path was ok, now check the filename if it doesn't contain
  782. ;    wildcard chars.
  783. ;
  784. check_fname:
  785.     test    flags,HAS_WILD
  786.     jz    checkfn1
  787.     jmp    ready
  788. ;
  789. checkfn1:
  790.     ldesf    di,fullpath    ; make full path string
  791.     IFDEF    PASCAL
  792.     inc    di
  793.     ENDIF
  794.     lddsf    si,drive
  795.     IFDEF    PASCAL
  796.     inc    si
  797.     ENDIF
  798.     call    @strcpy
  799.     ldds    si,path
  800.     IFDEF    PASCAL
  801.     inc    si
  802.     ENDIF
  803.     call    @strcpy
  804.     test    flags,HAS_FNAME OR HAS_EXT
  805.     jnz    checkfn2
  806. ;
  807. ;    No filename, get the attribute of the directory
  808. ;
  809.     or    flags,IS_DIR
  810.     dec    di
  811.     mov    byte ptr es:[di],0    ; clear trailing '\'
  812.     dec    di
  813.     cmp    byte ptr es:[di],':'    ; root dir?
  814.     je    no_dirchk        ; then don't get attribute
  815.     ldds    dx,fullpath
  816.     IFDEF    PASCAL
  817.     inc    dx
  818.     ENDIF
  819.     mov    ax,4300h    ; get attribute
  820.     int    21h
  821.     mov    ds,dseg
  822.     jc    no_attrib    ; shouldn't happen
  823.     cmp    fail,0
  824.     jne    no_attrib
  825.     mov    ax,flags
  826.     mov    ah,cl
  827.     and    ah,7fh
  828.     mov    flags,ax
  829. no_dirchk:
  830.     jmp    ready
  831. ;
  832. no_attrib:
  833.     mov    ax,ERR_PATH
  834.     jmp    error_exit
  835. ;
  836. checkfn2:
  837.     ldds    si,fname
  838.     IFDEF    PASCAL
  839.     inc    si
  840.     ENDIF
  841.     call    @strcpy
  842.     ldds    si,ext
  843.     IFDEF    PASCAL
  844.     inc    si
  845.     ENDIF
  846.     call    @strcpy
  847. ;
  848.     mov    ah,2fh        ; get current DTA
  849.     int    21h        ; ES:BX has current DTA
  850.     push    bx
  851.     push    es
  852. ;
  853.     mov    ds,dseg
  854.     mov    dx,offset dfltpath
  855.     mov    ah,1ah        ; set DTA
  856.     int    21h
  857. ;
  858.     ldds    dx,fullpath
  859.     IFDEF    PASCAL
  860.     inc    dx
  861.     ENDIF
  862.     mov    cx,10110B    ; search all except label
  863.     mov    ah,4eh        ; search for first
  864.     int    21h
  865.     mov    ds,dseg
  866.     jc    no_file
  867.     cmp    fail,0
  868.     jne    no_file
  869. ;
  870.     mov    ax,flags
  871.     mov    ah,dfltpath+15h    ; file attributes into upper byte of flags
  872.     test    ah,10h        ; subdirectory?
  873.     jz    no_subdir
  874. ;
  875. ;    The filename specifies a subdirectory. Append it to the path.
  876. ;
  877.     ldesf    di,path
  878.     IFDEF    PASCAL
  879.     inc    di
  880.     ENDIF
  881.     mov    cx,-1
  882.     xor    ax,ax
  883.     repne scasb
  884.     dec    di
  885.     mov    si,offset dfltpath+1eh
  886.     call    @strcpy
  887.     mov    al,'\'
  888.     stosb
  889.     xor    al,al
  890.     stosb
  891.     ldes    di,fname
  892.     IFDEF    PASCAL
  893.     inc    di
  894.     ENDIF
  895.     stosb
  896.     ldes    di,ext
  897.     IFDEF    PASCAL
  898.     inc    di
  899.     ENDIF
  900.     stosb
  901.     mov    ax,flags
  902.     mov    ah,dfltpath+15h    ; file attributes into upper byte of flags
  903.     and    ah,7fh        ; make sure it's positive
  904.     and    al,NOT (HAS_FNAME OR HAS_EXT)
  905.     or    al,HAS_PATH
  906.     mov    flags,ax
  907.     jmp    short no_file
  908. ;
  909. no_subdir:
  910.     or    al,FILE_EXISTS
  911.     and    ah,7fh        ; make sure it's positive
  912.     mov    flags,ax
  913. ;
  914. no_file:
  915.     pop    ds
  916.     pop    dx
  917.     mov    ah,1ah
  918.     int    21h        ; restore DTA
  919. ;
  920. ready:
  921.     ldesf    di,fullpath    ; make full path string
  922.     IFDEF    PASCAL
  923.     inc    di
  924.     ENDIF
  925.     lddsf    si,drive
  926.     IFDEF    PASCAL
  927.     inc    si
  928.     ENDIF
  929.     call    @strcpy
  930.     ldds    si,path
  931.     IFDEF    PASCAL
  932.     inc    si
  933.     ENDIF
  934.     call    @strcpy
  935.     ldds    si,fname
  936.     IFDEF    PASCAL
  937.     inc    si
  938.     ENDIF
  939.     call    @strcpy
  940.     ldds    si,ext
  941.     IFDEF    PASCAL
  942.     inc    si
  943.     ENDIF
  944.     call    @strcpy
  945.     mov    ds,dseg
  946.     mov    ax,flags
  947. ;
  948. error_exit:
  949.     mov    ds,dseg
  950.     cmp    fail,0
  951.     je    nofail
  952.     mov    ax,ERR_CRITICAL
  953. ;
  954. nofail:
  955.     push    ax
  956.     cmp    ax,0
  957.     jge    no_error
  958.     ldesf    di,fullpath
  959.     mov    word ptr es:[di],0
  960. ;
  961. no_error:
  962.     lds    dx,save24
  963.     mov    ax,2524h
  964.     int    21h
  965.     IFDEF    PASCAL
  966.     ldesf    di,drive
  967.     call    @strlen
  968.     ldes    di,path
  969.     call    @strlen
  970.     ldes    di,fname
  971.     call    @strlen
  972.     ldes    di,ext
  973.     call    @strlen
  974.     ldes    di,fullpath
  975.     call    @strlen
  976.     ENDIF
  977.     pop    ax
  978. ;
  979.     ret
  980. ;
  981. checkpath endp
  982. ;
  983. ;
  984. ;e Returns TRUE if a file with name 'fname' exists.
  985. ;d Liefert TRUE wenn eine Datei mit dem Namen 'fname' existiert.
  986. ;
  987.     IFDEF    PASCAL
  988.     IFDEF    FARCALL
  989. exists    PROC far uses ds, fname: dword
  990.     ELSE
  991. exists    PROC near uses ds, fname: dword
  992.     ENDIF
  993.     ELSE
  994. exists    PROC    uses ds, fname: ptr byte
  995.     ENDIF
  996. ;
  997.     IFDEF    TC_HUGE
  998.     mov    ax,SEG my_data
  999.     mov    ds,ax
  1000.     ENDIF
  1001. ;
  1002.     IFDEF    PASCAL
  1003.     ldds    si,fname
  1004. ; for pascal, zero-terminate input string
  1005.     lodsb
  1006.     mov    bl,al
  1007.     xor    ah,ah
  1008.     mov    [si+bx],ah
  1009.     mov    dx,si
  1010.     ELSE
  1011.     ldds    dx,fname
  1012.     ENDIF
  1013. ;
  1014.     mov    ax,4300h    ; get file attributes
  1015.     int    21h
  1016.     mov    ax,0
  1017.     jc    exists_end
  1018.     test    cx,10h        ; directory?
  1019.     jnz    exists_end
  1020.     inc    ax
  1021. ;
  1022. exists_end:
  1023.     ret
  1024. ;
  1025. exists    endp
  1026. ;
  1027.     end
  1028.  
  1029.